package cn.maydaymemory.maydaycore.command.api;


import cn.maydaymemory.maydaycore.PluginMaydayCore;
import cn.maydaymemory.maydaycore.annotation.CommandHandler;
import cn.maydaymemory.maydaycore.annotation.SubCommandStructureHandler;
import cn.maydaymemory.maydaycore.message.util.EdgingUtil;
import cn.maydaymemory.maydaycore.message.util.NeatText;
import cn.maydaymemory.maydaycore.message.util.PageMessage;
import cn.maydaymemory.maydaycore.configuration.LanguageManager;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class CommandStructureExecutor {
    private CommandStructure structure;
    private CommandSender sender;
    private PageMessage helper;
    private NeatText neatHelperText;
    private boolean helperEnable;
    private LanguageManager language;
    private List<String> complete;
    private boolean titled=false;
    private boolean prefixed = false;

    public CommandStructureExecutor(CommandStructure structure){
        this.structure=structure;
        this.helperEnable=true;
        this.language = PluginMaydayCore.getInstance().getLanguage();
        this.complete = new ArrayList<>();
        neatHelperText = new NeatText();
        for(Method method:structure.getClass().getDeclaredMethods()) {
            method.setAccessible(true);
            CommandHandler handler = method.getDeclaredAnnotation(CommandHandler.class);
            if (handler != null) {
                StringBuilder pars=new StringBuilder();
                for(String par:handler.parameters()){
                    pars.append(par);
                    pars.append(" ");
                }
                String font = "§f"+handler.name()+" "+pars.toString()+" → §7"+handler.description();
                neatHelperText.width(60).addText(font,true);

                if(!complete.contains(handler.name())) complete.add(handler.name());
            }
        }
        for(Method method:structure.getClass().getDeclaredMethods()) {
            method.setAccessible(true);
            SubCommandStructureHandler handler = method.getDeclaredAnnotation(SubCommandStructureHandler.class);
            if (handler != null) {
                String font = "§f"+handler.name()+" → §7"+handler.description();
                neatHelperText.width(60).addText(font,true);

                if(!complete.contains(handler.name())) complete.add(handler.name());
            }
        }
        this.helper = new PageMessage(neatHelperText.getTexts()).stepLength(5);
    }

    public void excute(String name,String label,String[] args){
        if(sender==null) return;
        try{
            YamlConfiguration lang = language.getLang();
            if(lang==null) lang= language.getDefaultLang();
            if(lang==null) lang= PluginMaydayCore.getInstance().getLanguage().getLang();
            boolean invoked=false;
            boolean format=true;
            boolean permit=false;
            if(name.equalsIgnoreCase("help")&&helperEnable){
                if(args==null||args.length<1){
                    sendHelp(1);
                    return;
                }
                sendHelp(Integer.valueOf(args[0]));
                return;
            }
            for(Method method:structure.getClass().getDeclaredMethods()){
                method.setAccessible(true);
                CommandHandler handler=method.getAnnotation(CommandHandler.class);
                if(method.isAnnotationPresent(CommandHandler.class)){
                    if(handler.name().equalsIgnoreCase(name)){
                        invoked=true;
                        if(sender.hasPermission(handler.permission())){
                            permit=true;
                            if(args!=null&&args.length==handler.parameters().length){
                                format=false;
                                if(handler.playerOnly()){
                                    if(sender instanceof Player){
                                        Player p = (Player) sender;
                                        structure.redefine(p,label,args,method);
                                        break;
                                    } else {
                                        sender.sendMessage(lang.getString("player-only","Language mismatch(player-only)")+"");
                                    }
                                }else{
                                    structure.redefine(sender,label,args,method);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            for(Method method:structure.getClass().getDeclaredMethods()) {
                method.setAccessible(true);
                SubCommandStructureHandler handler = method.getAnnotation(SubCommandStructureHandler.class);
                if (method.isAnnotationPresent(SubCommandStructureHandler.class)) {
                    if (handler.name().equalsIgnoreCase(name)) {
                        CommandStructure child = getChildStructure(name);
                        if(child!=null) {
                            CommandStructureExecutor executor = structure.getChildStructureExecutor(child)
                                    .sender(sender)
                                    .language(language);
                            if(!executor.prefixed) executor.changeHelperPrefix(handler.prefix());
                            if(!executor.titled) executor.changeHelperTitle("§7"+handler.name() + "'s help");
                            if (args == null || args.length < 1) {
                                if (executor.helperEnable()) executor.sendHelp(1);
                                return;
                            }
                            if (args.length == 1) {
                                executor.excute(args[0], label, new String[0]);
                                return;
                            }
                            String[] par = new String[args.length - 1];
                            System.arraycopy(args, 1, par, 0, args.length - 1);
                            executor.excute(args[0], label, par);
                            return;
                        }
                    }
                }
            }
            if(!invoked){
                sender.sendMessage((lang.getString("wrong-command","Language mismatch(wrong-command)")+"").replaceAll("%sub_command%",name));
                return;
            }

            if(!permit){
                sender.sendMessage(lang.getString("no-permission","Language mismatch(no-permission)")+"");
                return;
            }
            if(format){
                sender.sendMessage(language.getLang().getString("format","Language mismatch(format)")+"");
            }
        }catch (IllegalArgumentException e){
            sender.sendMessage(language.getLang().getString("error","Language mismatch(error)")+"");
            Bukkit.getServer().getLogger().info(e.getMessage());
        } catch (Exception e){
            sender.sendMessage(e.getMessage());
            e.printStackTrace();
        }
    }
    public CommandStructureExecutor helperEnable(boolean enable){
        helperEnable=enable;
        return this;
    }
    public boolean helperEnable(){
        return helperEnable;
    }
    public CommandStructureExecutor changeHelperPrefix(String prefix){
        helper().messages(neatHelperText.getTexts(prefix));
        prefixed=true;
        return this;
    }
    public CommandStructureExecutor changeHelperTitle(String title){
        helper.title(EdgingUtil.getHeader(title,60));
        titled=true;
        return this;
    }
    public PageMessage helper(){ return helper; }
    public void sendHelp(int page){
        if(sender==null) return;
        sender.sendMessage(" ");
        helper.viewer(sender).sendMessages(page);
    }

    public CommandStructureExecutor language(LanguageManager language){
        if(language!=null)this.language = language;
        else this.language=PluginMaydayCore.getInstance().getLanguage();
        return this;
    }
    public LanguageManager language(){ return language; }

    public CommandStructureExecutor sender(CommandSender sender){
        this.sender=sender;
        return this;
    }
    public CommandSender sender(){ return sender; }

    public List<String> complete(){ return new ArrayList<>(complete); }

    public CommandStructure getChildStructure(String name) throws InvocationTargetException, IllegalAccessException {
        for(Method method:structure.getClass().getDeclaredMethods()) {
            method.setAccessible(true);
            SubCommandStructureHandler handler = method.getAnnotation(SubCommandStructureHandler.class);
            if (method.isAnnotationPresent(SubCommandStructureHandler.class)) {
                if (handler.name().equalsIgnoreCase(name)) {
                    structure.redefine(null,null,null,null);
                    Object obj = method.invoke(structure);
                    if(obj==null) continue;
                    if(!(obj instanceof CommandStructure)) continue;
                    return (CommandStructure) obj;
                }
            }
        }
        return null;
    }
}
